using Sage.WindowsProcess.Events;
using System.Diagnostics;
using System.Runtime.Versioning;

namespace Sage.WindowsProcess
{
    /// <summary>
    /// 管理外部进程的启动、停止和监控的类。提供进程生命周期管理、IO重定向和资源管理功能。
    /// </summary>
    public partial class ExternalProcessManager : IDisposable, IAsyncDisposable
    {
        private Process? _process;
        private readonly string _processName;
        private readonly string _processPath;
        private bool _disposed;
        private readonly Lock _lock = new();
        private Timer? _monitoringTimer;
        private ProcessStartInfo? _startInfo;
        private bool _autoRestart;
        private int _restartDelayMs = 1000;
        private int _maxRestartAttempts = 3;
        private int _restartAttempts;
        private ProcessPriorityClass _processPriority = ProcessPriorityClass.Normal;

        /// <summary>
        /// 初始化 ExternalProcessManager 类的新实例。
        /// </summary>
        /// <param name="processName">要管理的进程的名称（不包含扩展名）。</param>
        /// <param name="processPath">要启动的程序的完整路径。</param>
        /// <exception cref="ArgumentNullException">当 processName 或 processPath 为 null 时抛出。</exception>
        /// <exception cref="ArgumentException">当 processName 或 processPath 为空或仅包含空白字符时抛出。</exception>
        public ExternalProcessManager(string processName, string processPath)
        {
            _processName = processName ?? throw new ArgumentNullException(nameof(processName));
            _processPath = processPath ?? throw new ArgumentNullException(nameof(processPath));

            if (string.IsNullOrWhiteSpace(_processName))
                throw new ArgumentException("进程名称不能为空。", nameof(processName));

            if (string.IsNullOrWhiteSpace(_processPath))
                throw new ArgumentException("进程路径不能为空。", nameof(processPath));
        }

        /// <summary>
        /// 获取或设置一个值，该值指示是否重定向标准输出和错误。
        /// </summary>
        public bool RedirectOutput { get; set; } = true;

        /// <summary>
        /// 获取或设置一个值，该值指示是否创建新窗口。
        /// 对于控制台应用，设置为false会显示窗口；对于GUI应用则不影响其窗口显示。
        /// </summary>
        public bool CreateNoWindow { get; set; } = true;

        /// <summary>
        /// 获取或设置进程的工作目录。默认为进程可执行文件所在的目录。
        /// </summary>
        public string? WorkingDirectory { get; set; }

        /// <summary>
        /// 获取或设置启动进程时要使用的命令行参数。
        /// </summary>
        public string? Arguments { get; set; }

        /// <summary>
        /// 获取或设置一个值，该值指示是否在进程退出时自动重启它。
        /// </summary>
        public bool AutoRestart
        {
            get => _autoRestart;
            set
            {
                _autoRestart = value;
                if (_autoRestart && _process != null && !_process.HasExited)
                {
                    // 确保已经注册了进程退出事件
                    _process.EnableRaisingEvents = true;
                }
            }
        }

        /// <summary>
        /// 获取或设置自动重启尝试之间的延迟（以毫秒为单位）。
        /// </summary>
        /// <exception cref="ArgumentException">当值小于或等于0时抛出。</exception>
        public int RestartDelayMs
        {
            get => _restartDelayMs;
            set => _restartDelayMs = value > 0 ? value : throw new ArgumentException("重启延迟必须大于0。");
        }

        /// <summary>
        /// 获取或设置最大自动重启尝试次数。设置为0表示无限重试。
        /// </summary>
        /// <exception cref="ArgumentException">当值小于0时抛出。</exception>
        public int MaxRestartAttempts
        {
            get => _maxRestartAttempts;
            set => _maxRestartAttempts = value >= 0 ? value : throw new ArgumentException("最大重启尝试次数不能为负数。");
        }

        /// <summary>
        /// 获取或设置进程的优先级。
        /// </summary>
        public ProcessPriorityClass ProcessPriority
        {
            get => _processPriority;
            set
            {
                _processPriority = value;

                // 如果进程已经在运行，立即应用新的优先级
                if (IsRunning && _process != null)
                {
                    try
                    {
                        _process.PriorityClass = _processPriority;
                    }
                    catch (Exception ex)
                    {
                        OnProcessError(new ProcessErrorEventArgs($"设置进程优先级失败: {ex.Message}", ex));
                    }
                }
            }
        }

        /// <summary>
        /// 获取当前进程实例的ID，如果进程未运行则返回null。
        /// </summary>
        public int? ProcessId => _process?.Id;

        /// <summary>
        /// 获取一个值，该值指示进程是否当前正在运行。
        /// </summary>
        public bool IsRunning
        {
            get
            {
                lock (_lock)
                {
                    try
                    {
                        return _process != null && !_process.HasExited;
                    }
                    catch (InvalidOperationException)
                    {
                        // 进程可能已经退出
                        return false;
                    }
                }
            }
        }

        /// <summary>
        /// 启动外部程序，如果程序尚未运行。
        /// </summary>
        /// <param name="timeout">等待进程启动的超时时间（毫秒）。指定0表示无限等待。</param>
        /// <returns>如果进程成功启动或已经在运行，则为true；否则为false。</returns>
        [SupportedOSPlatform("windows")]
        public bool StartProcess(int timeout = 30000)
        {
            lock (_lock)
            {
                if (IsRunning)
                {
                    OnProcessAlreadyRunning(new ProcessEventArgs(_process!));
                    return true;
                }

                if (!File.Exists(_processPath))
                {
                    OnProcessError(new ProcessErrorEventArgs($"启动失败：程序路径不存在 - {_processPath}"));
                    return false;
                }

                try
                {
                    // 尝试查找已运行的进程
                    var runningProcesses = Process.GetProcessesByName(_processName);
                    if (runningProcesses.Length > 0)
                    {
                        _process = runningProcesses[0];
                        OnProcessAlreadyRunning(new ProcessEventArgs(_process));

                        // 检查是否需要监控
                        StartMonitoringIfEnabled();

                        return true;
                    }

                    // 初始化进程启动信息
                    InitializeProcessStartInfo();

                    // 创建新的Process实例
                    _process = new Process
                    {
                        StartInfo = _startInfo!,
                        EnableRaisingEvents = true
                    };

                    // 订阅事件
                    SubscribeToProcessEvents();

                    // 启动进程
                    bool started = _process.Start();

                    if (started)
                    {
                        OnProcessStarted(new ProcessEventArgs(_process));

                        if (RedirectOutput)
                        {
                            // 只有在重定向输出时才开始异步读取
                            _process.BeginOutputReadLine();
                            _process.BeginErrorReadLine();
                        }

                        // 如果指定了超时，等待进程启动完成
                        if (timeout > 0)
                        {
                            try
                            {
                                if (!_process.WaitForInputIdle(timeout))
                                {
                                    OnProcessError(new ProcessErrorEventArgs($"进程启动超时: {timeout}ms"));
                                }
                            }
                            catch (InvalidOperationException)
                            {
                                // 某些进程不支持WaitForInputIdle，忽略异常
                            }
                        }

                        // 启动监控定时器
                        StartMonitoringIfEnabled();

                        // 设置进程优先级
                        try
                        {
                            _process.PriorityClass = _processPriority;
                        }
                        catch (Exception ex)
                        {
                            OnProcessError(new ProcessErrorEventArgs($"设置进程优先级失败: {ex.Message}", ex));
                            // 继续执行，不因为设置优先级失败而中断启动过程
                        }

                        // 重置重启尝试计数
                        _restartAttempts = 0;

                        return true;
                    }
                    else
                    {
                        OnProcessError(new ProcessErrorEventArgs("启动失败：无法启动进程。"));
                        return false;
                    }
                }
                catch (Exception ex)
                {
                    OnProcessError(new ProcessErrorEventArgs($"启动失败: {ex.Message}", ex));
                    return false;
                }
            }
        }

        /// <summary>
        /// 停止外部程序，如果程序正在运行。
        /// </summary>
        /// <param name="timeout">等待进程退出的超时时间（毫秒）。指定0表示无限等待。</param>
        /// <returns>如果进程成功停止或已经不在运行，则为true；否则为false。</returns>
        public bool StopProcess(int timeout = 5000)
        {
            lock (_lock)
            {
                // 临时禁用自动重启
                bool originalAutoRestart = _autoRestart;
                _autoRestart = false;

                try
                {
                    if (_process == null || _process.HasExited)
                    {
                        return true;
                    }

                    // 停止监控定时器
                    StopMonitoring();

                    // 尝试正常关闭
                    try
                    {
                        _process.CloseMainWindow();

                        // 等待进程退出
                        if (timeout > 0)
                        {
                            if (!_process.WaitForExit(timeout))
                            {
                                // 如果正常关闭失败，强制终止
                                _process.Kill(true); // 终止整个进程树
                                _process.WaitForExit();
                            }
                        }
                        else
                        {
                            _process.Kill(true);
                            _process.WaitForExit();
                        }

                        OnProcessStopped(new ProcessEventArgs(_process));
                        return true;
                    }
                    catch (Exception ex)
                    {
                        OnProcessError(new ProcessErrorEventArgs($"停止进程失败: {ex.Message}", ex));
                        return false;
                    }
                }
                finally
                {
                    // 恢复原始的自动重启设置
                    _autoRestart = originalAutoRestart;
                }
            }
        }

        /// <summary>
        /// 重启正在运行的进程。如果进程未运行，则只启动它。
        /// </summary>
        /// <param name="startTimeout">启动超时（毫秒）</param>
        /// <param name="stopTimeout">停止超时（毫秒）</param>
        /// <returns>如果重启成功，则为true；否则为false。</returns>
        [SupportedOSPlatform("windows")]
        public bool RestartProcess(int startTimeout = 30000, int stopTimeout = 5000)
        {
            lock (_lock)
            {
                // 临时禁用自动重启
                bool originalAutoRestart = _autoRestart;
                _autoRestart = false;

                try
                {
                    if (IsRunning)
                    {
                        // 先停止进程
                        if (!StopProcess(stopTimeout))
                            return false;
                    }

                    // 再启动进程
                    return StartProcess(startTimeout);
                }
                finally
                {
                    // 恢复原始的自动重启设置
                    _autoRestart = originalAutoRestart;
                }
            }
        }

        /// <summary>
        /// 向进程的标准输入写入数据。
        /// </summary>
        /// <param name="input">要写入的输入字符串。</param>
        /// <returns>如果写入成功，则为true；否则为false。</returns>
        public bool WriteToStandardInput(string input)
        {
            lock (_lock)
            {
                if (!IsRunning || _process?.StandardInput == null)
                {
                    OnProcessError(new ProcessErrorEventArgs("无法写入标准输入：进程未运行或标准输入未重定向。"));
                    return false;
                }

                try
                {
                    _process.StandardInput.WriteLine(input);
                    _process.StandardInput.Flush();
                    return true;
                }
                catch (Exception ex)
                {
                    OnProcessError(new ProcessErrorEventArgs($"写入标准输入失败: {ex.Message}", ex));
                    return false;
                }
            }
        }

        /// <summary>
        /// 初始化进程启动信息。
        /// </summary>
        private void InitializeProcessStartInfo()
        {
            _startInfo = new ProcessStartInfo
            {
                FileName = _processPath,
                WorkingDirectory = WorkingDirectory ?? Path.GetDirectoryName(_processPath) ?? string.Empty,
                UseShellExecute = false, // 始终为false以支持可能的重定向
                RedirectStandardOutput = RedirectOutput,
                RedirectStandardError = RedirectOutput,
                RedirectStandardInput = RedirectOutput,
                CreateNoWindow = CreateNoWindow,
                Arguments = Arguments ?? string.Empty
            };
        }

        /// <summary>
        /// 订阅进程事件。
        /// </summary>
        [SupportedOSPlatform("windows")]
        private void SubscribeToProcessEvents()
        {
            if (_process == null) return;

            // 启用重定向时再进行事件订阅
            if (RedirectOutput)
            {
                _process.OutputDataReceived += (sender, e) =>
                {
                    if (!string.IsNullOrEmpty(e.Data))
                    {
                        OnOutputReceived(e.Data);
                    }
                };

                _process.ErrorDataReceived += (sender, e) =>
                {
                    if (!string.IsNullOrEmpty(e.Data))
                    {
                        OnErrorReceived(e.Data);
                    }
                };
            }

            _process.Exited += Process_Exited;
        }

        /// <summary>
        /// 取消订阅进程事件。
        /// </summary>
        [SupportedOSPlatform("windows")]
        private void UnsubscribeFromProcessEvents()
        {
            if (_process == null) return;

            try
            {
                _process.Exited -= Process_Exited;
            }
            catch (Exception)
            {
                // 可能在进程已经退出后调用，忽略异常
            }
        }

        /// <summary>
        /// 处理进程退出事件。
        /// </summary>
        [SupportedOSPlatform("windows")]
        private void Process_Exited(object? sender, EventArgs e)
        {
            if (sender is not Process process) return;

            // 获取退出代码
            int exitCode;
            try
            {
                exitCode = process.ExitCode;
            }
            catch
            {
                exitCode = -1; // 无法获取退出代码
            }

            var args = new ProcessExitedEventArgs(process, exitCode);
            OnProcessExited(args);

            // 处理自动重启
            if (_autoRestart && (_maxRestartAttempts == 0 || _restartAttempts < _maxRestartAttempts))
            {
                _restartAttempts++;

                // 使用Timer延迟重启，避免立即重启可能导致的问题
                Timer? restartTimer = null;
                restartTimer = new Timer(_ =>
                {
                    try
                    {
                        StartProcess();
                    }
                    finally
                    {
                        restartTimer?.Dispose();
                    }
                }, null, _restartDelayMs, Timeout.Infinite);
            }
        }

        /// <summary>
        /// 异步释放资源
        /// </summary>
        [SupportedOSPlatform("windows")]
        public async ValueTask DisposeAsync()
        {
            // 执行异步清理
            await DisposeAsyncCore();

            // 执行同步清理
            Dispose(false);

            // 抑制终结器
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// 异步资源释放的核心逻辑
        /// </summary>
        [SupportedOSPlatform("windows")]
        protected virtual async ValueTask DisposeAsyncCore()
        {
            if (_disposed)
                return;

            try
            {
                // 停止监控
                StopMonitoring();

                // 异步停止进程
                if (_process != null && !_process.HasExited)
                {
                    await StopProcessAsync();
                }
            }
            catch
            {
                // 忽略异常
            }
        }

        /// <summary>
        /// 实现IDisposable接口的Dispose方法。
        /// </summary>
        [SupportedOSPlatform("windows")]
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// 释放托管和非托管资源。
        /// </summary>
        /// <param name="disposing">如果为true，则释放托管和非托管资源；如果为false，则只释放非托管资源。</param>
        [SupportedOSPlatform("windows")]
        protected virtual void Dispose(bool disposing)
        {
            if (_disposed) return;

            if (disposing)
            {
                // 释放托管资源
                StopMonitoring();
                StopProcess();
                UnsubscribeFromProcessEvents();

                if (_process != null)
                {
                    _process.Dispose();
                    _process = null;
                }
            }

            _disposed = true;
        }

        /// <summary>
        /// 析构函数，在对象被垃圾回收时调用。
        /// </summary>
        [SupportedOSPlatform("windows")]
        ~ExternalProcessManager()
        {
            Dispose(false);
        }
    }
}
